package com.cskaoyan.javase.array._4operation._4copy;

import java.util.Arrays;

/**
 * 数组元素的拷贝,在开发中,手写的机会很少,但源码中很常见
 * 数组的最大缺点是长度不可变,但是我们又希望能够利用数组的随机访问
 *      所以在开发中需要去改进数组:
 *      如果有一种支持随机访问存在下标,并且可以自动扩容的数组,肯定是更好的选择
 * 这其实就是Java集合体系中ArrayList类,它是一种可自动扩容的数组
 * 是开发中最常用的集合容器,几乎等同于数组,基本上开发中完全取代数组
 *
 * ArrayList它的底层实现,仍然是基于数组,所以他有下标,有随机访问
 * 并且可以自动扩容,就是通过数组拷贝实现的:
 *      创建一个更长的新数组,然后将原先的数组中的元素全部拷贝过去
 *
 * 也就是说如果想要实现数组元素"真正意义上的"删除和新增，一般需要使用数组的拷贝。
 *
 * @since 10:55
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        int[] result = realInsertElement2IntArr(arr, -100);
        System.out.println(Arrays.toString(result));
        System.out.println("----------------------");

        int[] old = {1, 2, 312, 3, 21, 3, 123, 12, 3, 12, 1, 2, 13, 1, 1};
        int[] result2 = realDeleteElements2IntArr(old, 2);
        System.out.println(Arrays.toString(result2));
    }

    // 需求: 给出一个int数组,要求真正删除目标元素,但目标元素的个数可能不唯一

    /**
     * 通过数组拷贝,真正意义上删除元素
     * 该方法需要创建一个新数组,并把删除元素后的新数组返回
     *
     * @param target 被删除元素的目标数组
     * @param delete 被删除的目标元素,在目标数组中,该元素可能不唯一
     * @return int[]
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/08/19 11:15
     */
    public static int[] realDeleteElements2IntArr(int[] target, int delete) {
        // 1.创建新数组,新数组的长度 = 老数组的长度 - 被删除目标元素的个数
        // 统计目标元素的个数,统计个数需要计数器
        int deleteElementsCount = 0;
        // 遍历老数组,计算出被删除的元素的个数
        for (int ele : target) {
            if (ele == delete) {
                deleteElementsCount++;
            }
        }
        // 代码运行到这里,count的取值就是被删除的目标元素的个数
        int[] result = new int[target.length - deleteElementsCount];

        // 2.给新数组赋值,这个过程中需要"删除"目标元素.
        /*
            怎么才能够实现"删除"目标元素的效果?
            新数组已经创建出来了,它的长度恰好是删除元素后数组的长度
            这时,只需要遍历老数组,然后在给新数组赋值时,过滤掉那些被删除的元素
            所以元素的删除,其实是过滤老数组中的元素
         */
        int newIndex = 0;
        for (int ele : target) {
            if (ele == delete) {
                // 过滤掉,不进行赋值
                continue;
            }
            // 不是被删除的目标元素,留下它,赋值给新数组
            result[newIndex] = ele;
            newIndex++;
        }
        // 以上就完成了新数组的赋值,就完成了删除操作
        return result;
    }

    // 需求: 给出一个int数组,要求真正新增一个元素
    /*
        如何实现?
        首先数组的长度是不可变的,那么这个操作有没有可能直接在原先数组中实现??
        绝无可能,所以必须创建新数组实现
        大致思路是:
            1.首先需要明确新数组的长度，初始化创建这个新数组。
            2.然后遍历原先的数组，过滤掉（或者新增）一些元素，给新数组赋值。
     */

    /**
     * 通过数组拷贝,真正意义上插入一个元素
     * 该方法需要创建一个新数组,并把插入元素的新数组返回
     *
     * @param target 被插入元素的数组
     * @param element 被插入的元素
     * @return int[]
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/08/19 11:04
     */
    public static int[] realInsertElement2IntArr(int[] target, int element) {
        // 1.创建新数组,新数组的长度 = 老数组的长度 + 1
        int[] result = new int[target.length + 1];
        // 2.给新数组赋值
        // 新数组无非就是在老数组的基础上,新增了一个元素,所以仍然需要将老数组中的所有元素添加进新数组
        // 定义一个变量从0开始,表示新数组的下标,用于给新数组赋值
        int newIndex = 0;
        for (int ele : target) {
            // 因为是要赋值新数组,所以遍历老数组时用增强for是完全可以的
            // 接下来开始给新数组赋值
            result[newIndex] = ele;
            newIndex++;
        }
        // 以上增强for循环就完成了将老数组中的元素,全部赋值进新数组
        // 现在新数组还剩下最后一个空位置,就是新数组的最后一个元素,于是赋值给目标新增元素
        result[result.length - 1] = element;
        return result;
    }


}
